# src/bot_api_v1/app/services/business/config_service.py

import json
import logging
from sqlalchemy import select

# 导入同步和异步的组件
from bot_api_v1.app.core.cache import redis_client, sync_redis_client
from bot_api_v1.app.db.session import async_session_maker, get_sync_db_session
from bot_api_v1.app.models.meta_config import MetaConfig

logger = logging.getLogger(__name__)

class ConfigService:
    """
    [最终完整版] 动态配置服务。
    同时支持异步(FastAPI)和同步(Celery)调用。
    """
    _cache_prefix_key = "config:key:"
    _cache_prefix_type = "config:type:"
    _cache_ttl = 3600 # 缓存1小时

    # --- 异步方法 (FastAPI 使用) ---

    @classmethod
    async def get(cls, key: str, default: any = None) -> any:
        cache_key = f"{cls._cache_prefix_key}{key}"
        try:
            cached_value = await redis_client.get(cache_key)
            if cached_value is not None:
                return json.loads(cached_value)
        except Exception as e:
            logger.warning(f"Redis get failed for key {key}: {e}")

        async with async_session_maker() as session:
            config_obj = (await session.execute(
                select(MetaConfig).where(MetaConfig.config_key == key, MetaConfig.is_active == True)
            )).scalar_one_or_none()

        value_to_cache = config_obj.config_value if config_obj else default
        try:
            await redis_client.set(cache_key, json.dumps(value_to_cache), ex=cls._cache_ttl)
        except Exception as e:
            logger.warning(f"Redis set failed for key {key}: {e}")
        return value_to_cache

    @classmethod
    async def get_by_type(cls, config_type: str) -> list[dict]:
        cache_key = f"{cls._cache_prefix_type}{config_type}"
        try:
            cached_list_str = await redis_client.get(cache_key)
            if cached_list_str:
                return json.loads(cached_list_str)
        except Exception as e:
            logger.warning(f"Redis get failed for type {config_type}: {e}")

        async with async_session_maker() as session:
            stmt = select(MetaConfig).where(MetaConfig.config_type == config_type, MetaConfig.is_active == True).order_by(MetaConfig.sort.asc())
            configs = (await session.execute(stmt)).scalars().all()

        config_list = [{"key": c.config_key, "value": c.config_value, "description": c.description} for c in configs]
        try:
            if config_list:
                await redis_client.set(cache_key, json.dumps(config_list), ex=cls._cache_ttl)
        except Exception as e:
            logger.warning(f"Redis set failed for type {config_type}: {e}")
        return config_list
    
    # --- 同步方法 (Celery 使用) ---

    @classmethod
    def get_sync(cls, key: str, default: any = None) -> any:
        """
        [同步版本] 根据 key 获取单个配置。
        """
        cache_key = f"{cls._cache_prefix_key}{key}"
        try:
            cached_value = sync_redis_client.get(cache_key)
            if cached_value is not None:
                return json.loads(cached_value)
        except Exception as e:
            logger.warning(f"[SYNC] Redis get failed for key {key}: {e}")

        with get_sync_db_session() as session:
            config_obj = session.execute(
                select(MetaConfig).where(MetaConfig.config_key == key, MetaConfig.is_active == True)
            ).scalar_one_or_none()

        value_to_cache = config_obj.config_value if config_obj else default
        try:
            sync_redis_client.set(cache_key, json.dumps(value_to_cache), ex=cls._cache_ttl)
        except Exception as e:
            logger.warning(f"[SYNC] Redis set failed for key {key}: {e}")
        return value_to_cache

    @classmethod
    def get_by_type_sync(cls, config_type: str) -> list[dict]:
        """
        [新增的同步版本] 根据 type 获取一个配置列表。
        """
        cache_key = f"{cls._cache_prefix_type}{config_type}"
        try:
            cached_list_str = sync_redis_client.get(cache_key)
            if cached_list_str:
                return json.loads(cached_list_str)
        except Exception as e:
            logger.warning(f"[SYNC] Redis get failed for type {config_type}: {e}")
            
        config_list = []
        with get_sync_db_session() as session:
            stmt = (
                select(MetaConfig)
                .where(MetaConfig.config_type == config_type, MetaConfig.is_active == True)
                .order_by(MetaConfig.sort.asc())
            )
            configs = session.execute(stmt).scalars().all()
            config_list = [
                {"key": c.config_key, "value": c.config_value, "description": c.description} for c in configs
            ]
        
        try:
            if config_list:
                sync_redis_client.set(cache_key, json.dumps(config_list), ex=cls._cache_ttl)
        except Exception as e:
            logger.warning(f"[SYNC] Redis set failed for type {config_type}: {e}")
        return config_list
        
    # --- 启动时预热缓存的方法 (保持不变) ---
    @classmethod
    async def load_all_to_cache(cls):
        # ... 此方法保持不变，它会在应用启动时预热缓存 ...
        logger.info("Pre-heating dynamic configurations into cache...")
        configs_by_key = {}
        configs_by_type = {}

        try:
            async with async_session_maker() as session:
                stmt = select(MetaConfig).where(MetaConfig.is_active == True)
                all_configs = (await session.execute(stmt)).scalars().all()

            for config in all_configs:
                configs_by_key[f"{cls._cache_prefix_key}{config.config_key}"] = json.dumps(config.config_value)
                if config.config_type not in configs_by_type:
                    configs_by_type[config.config_type] = []
                configs_by_type[config.config_type].append(config)

            configs_to_cache_by_type = {}
            for config_type, configs in configs_by_type.items():
                configs.sort(key=lambda c: c.sort)
                formatted_list = [{"key": c.config_key, "value": c.config_value, "description": c.description} for c in configs]
                cache_key = f"{cls._cache_prefix_type}{config_type}"
                configs_to_cache_by_type[cache_key] = json.dumps(formatted_list)
            
            async with redis_client.pipeline() as pipe:
                if configs_by_key:
                    pipe.mset(configs_by_key)
                if configs_to_cache_by_type:
                    pipe.mset(configs_to_cache_by_type)
                await pipe.execute()
            
            logger.info(f"Successfully cached {len(configs_by_key)} config keys and {len(configs_to_cache_by_type)} config types.")

        except Exception as e:
            logger.error(f"Failed to pre-heat configs to cache: {e}", exc_info=True)

    @classmethod
    async def clear_cache(cls, key: str = None, config_type: str = None):
        """当配置更新时，清理相关缓存"""
        if key:
            await redis_client.delete(f"{cls._cache_prefix_key}{key}")
        if config_type:
            await redis_client.delete(f"{cls._cache_prefix_type}{config_type}")